#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os,sys,re
from wwpy.db.DBI import DBI,DBC
from wwpy.util.Shell import Shell
from wwpy.util.Time import Time
from wwpy.util.Wrapper import capturer
from wwpy.tms.conf.node import local_node

class Tasker(object):
    
    def __init__(self,cron_file='/var/spool/cron/root',date=None,coding='utf8'):
        self.cron_file=cron_file
        self.coding=coding
        self.dbi=self._dbi
        if date is not None:
            date=Time.date_format(date)
        else:
            date=Time.today()
        self.today=date
        
    @property
    def cron_tasks(self):
        """
        00 12 * * * echo 123
        """
        tasks=[]
        f=open(self.cron_file,'r')
        for line in f:
            line=line[:-1]
            if (not line) or line.startswith('#'):
                continue
            tasks.append(line)
        f.close()
        return tasks
        
    @property
    def _dbi(self):
        dbi=DBI(coding=self.coding,**DBC().db_cron_tms)
        return dbi
        
    @property
    def task_table(self):
        return 'tms_task'
    
    @property
    def task_record_table(self):
        return 'tms_task_record'
    
    @property
    def _task_table_fields(self):
        fields=[
            "id bigint(20) AUTO_INCREMENT PRIMARY KEY COMMENT '任务ID'",
            "name varchar(30) COMMENT '任务名称'",
            "cate varchar(30) COMMENT '任务产品线'",
            "timer varchar(30) COMMENT '定时表达式: * * * * *'",
            "cmd varchar(1000) COMMENT '运行的命令'",
            "host varchar(30) DEFAULT '10.5.20.15' COMMENT '任务运行的主机'",
            "user varchar(20) DEFAULT 'root' COMMENT '任务权限用户'",
            "doer varchar(30) DEFAULT '王伟' COMMENT '负责人'",
            "is_sched tinyint(1) DEFAULT 1 COMMENT '是否调度 1:是 0:否' ",
            "intro varchar(100) COMMENT '任务介绍'",
        ]
        return fields
    
    def create_task_table(self):
        if self.dbi.has_table(self.task_table):
            self.dbi.delete(self.task_table,is_drop=True)
        self.dbi.create(self.task_table,self._task_table_fields)
        
    def load_cron_tasks(self):
        self.create_task_table()
        for task in self.cron_tasks:
            task_info=re.split(r'\s+',task,5)
            timer,cmd=' '.join(str(t) for t in task_info[:5]),task_info[5].strip()
            self.dbi.insert(self.task_table,fields=['timer','cmd'],values=(timer,cmd))
            
    @property
    def host(self):
        cmd="/sbin/ifconfig |perl -wne 'do{print $1 if /inet addr:([^\s]+)/} && last'"
        shell=Shell(cmd)
        shell.call()
        host=shell.status.get('retstr',None)
        return host
    
    @property
    def tasks(self):
        if not self.dbi.has_table(self.task_table):
            self._load_tasks()
        host=local_node.host if hasattr(local_node,'host') else self.host
        sql="SELECT id,timer,cmd FROM %s WHERE host='%s' AND is_sched=1 " % (self.task_table,host)
        def row_func(info,row):
            if info is None:
                info={}
            info[row[0]]=dict(id=row[0],timer=row[1],cmd=row[2])
            return info
        tasks=self.dbi.fetch(sql,row_func=row_func)
        return tasks or {}
        
    def do_task(self,task,is_drop=False):
        task_id,cmd=task.get('id'),task.get('cmd')
        shell=Shell(cmd)
        shell.call()
        task_record=shell.status
        task_record['task_id']=str(task_id)
        self.insert_task_record(task_record)
        return task_record
    
    def redo_task(self,task):
        task_id=task.get('id') or task.get('task_id')
        task['id']=task_id
        return self.do_task(task)
    
    @property
    def _task_record_table_fields(self):
        fields=[
            "id bigint(20) AUTO_INCREMENT PRIMARY KEY COMMENT '记录ID'",
            "task_id bigint(20) COMMENT '任务ID'",
            "cmd varchar(1000) COMMENT '运行的命令'",
            "state tinyint(1) COMMENT '返回状态 0:成功 1:失败 -1:未执行'",
            "start_time datetime COMMENT '开始时间'",
            "end_time datetime COMMENT '结束时间'",
            "elapse double COMMENT '程序运行时间 秒'",
            "pid int(11) COMMENT '任务运行PID'",
            "retcode int(11) COMMENT '执行返回编号值'",
            "retstr varchar(1000) COMMENT '执行返回字符串'",
            "error varchar(100) COMMENT '错误信息'",
        ]
        return fields
    
    def create_task_record_table(self,is_drop=True):
        if is_drop:
            self.dbi.delete(self.task_record_table,is_drop=is_drop)
        if not self.dbi.has_table(self.task_record_table):
            self.dbi.create(self.task_record_table,self._task_record_table_fields)
    
    def insert_task_record(self,task_record,is_drop=False):
        self.create_task_record_table(is_drop)
        fields=['task_id','cmd','state','start_time','end_time','elapse','pid','retcode','retstr','error']
        self.dbi.insert(self.task_record_table,fields=fields,
                        values=tuple(map(lambda field:str(task_record.get(field)),fields)),)
        
    @property
    def task_records(self):
        sql="SELECT task_id,cmd,state,start_time,end_time,elapse,pid,retcode,retstr,error FROM %s WHERE LEFT(start_time,10)='%s' " % (self.task_record_table,self.today)
        def row_func(info,row):
            if info is None:
                info=[]
            info.append(dict(task_id=row[0],cmd=row[1],state=row[2],start_time=row[3],end_time=row[4],elapse=row[5],
                             pid=row[6],retcode=row[7],retstr=row[8],error=row[9]))
            return info
        rows=self.dbi.fetch(sql,row_func=row_func)
        return rows
        
    @capturer()
    def show_tasks(self,sep='\t'):
        sign='*' * 40
        title='tms tasks'
        print sign+title+sign
        for task_id,task in sorted(self.tasks.iteritems(),key=lambda r:r[0]):
            print sep.join([str(task['id']),task['timer'],task['cmd']])
        print sign * 2+'*' * len(title)
        
    @capturer()
    def show_task_records(self,sep=': '):
        sign='*' * 20
        title='tms task records'
        print sign+title+sign
        for task_record in self.task_records:
            for key,value in sorted(task_record.items()):
                print '%s%s%s' % (key,sep,value)
            print sign * 2+'*' * len(title)
            
    @property
    def failed_tasks(self):
        sql="SELECT task_id,cmd,state,start_time,end_time,elapse,pid,retcode,retstr,error FROM %s WHERE LEFT(start_time,10)='%s' and state!=0 " % (self.task_record_table,self.today)
        def row_func(info,row):
            if info is None:
                info=[]
            info.append(dict(task_id=row[0],cmd=row[1],state=row[2],start_time=row[3],end_time=row[4],elapse=row[5],
                             pid=row[6],retcode=row[7],retstr=row[8],error=row[9]))
            return info
        rows=self.dbi.fetch(sql,row_func=row_func)
        return rows
        
    @capturer()
    def show_failed_tasks(self,sep=': '):
        sign='*' * 20
        title='tms failed tasks'
        print sign+title+sign
        for task_record in self.failed_tasks:
            for key,value in sorted(task_record.items()):
                print '%s%s%s' % (key,sep,value)
            print sign * 2+'*' * len(title)
        
    def redo_failed_tasks(self):
        tids={}
        for task in self.failed_tasks:
            task_id=task.get('task_id')
            if task_id not in tids:
                tids[task_id]=1
                self.redo_task(task)
        
if __name__ == '__main__':
    t=Tasker('../conf/crontab.root',coding='gbk',date=20130604)
    #t.load_cron_tasks()
    stdout,res=t.show_tasks()
    print stdout
    #t.do_task(dict(id=112,timer='*/1 * * * *',cmd='ipconfig /all'))
    